<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <title>WEI BLOG</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  
  
  
    <link rel="alternate" href="/wei-blog/atom.xml" title="WEI BLOG" type="application/atom+xml">
  
  
    <link rel="shortcut icon" href="/wei-blog/favicon.png">
  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">

  
  
<link rel="stylesheet" href="/wei-blog/css/style.css">

  
  
  
  
<meta name="generator" content="Hexo 6.3.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a id="logo">WEI BLOG</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        
          <a class="main-nav-link" href="/wei-blog/."><i class="fa fa-home"></i> 首页</a>
        
          <a class="main-nav-link" href="/wei-blog/archives/"><i class="fa fa-archive"></i> 归档</a>
        
      </nav>
    </div>
    <div id="search-form">
      <div id="result-mask" class="hide"></div>
      <label><input id="search-key" type="text" autocomplete="off" placeholder="搜索"></label>
      <div id="result-wrap" class="hide">
        <div id="search-result"></div>
      </div>
      <div class="hide">
        <template id="search-tpl">
          <div class="item">
            <a href="/{path}" title="{title}">
              <div class="title">{title}</div>
              <!-- <div class="time">{date}</div> -->
              <div class="tags">{tags}</div>
            </a>
          </div>
        </template>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-缓存穿透、缓存雪崩、缓存击穿" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
    <div class="article-meta">
      
      <!-- <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2023-02-08T06:57:21.450Z" itemprop="datePublished">2023年02月08日</time>
</span> -->
      
      
        <span class="article-views">
  <!-- <i class="fa fa-views"></i>
  <i id="busuanzi_container_page_pv">
      <i id="busuanzi_value_page_pv"></i>
  </i> -->
</span>

      
      
<!-- <a href="/wei-blog/source/%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F%E3%80%81%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9%E3%80%81%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF/#comments" class="article-comment-link">
  
    
    
    
    
    
  
  <i class="fa fa-commt"></i>
  留言
</a> -->


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="缓存穿透"><a href="#缓存穿透" class="headerlink" title="缓存穿透"></a>缓存穿透</h1><blockquote>
<p>用户请求的数据在缓存中和数据库中都不存在，不断发起这样的请求，给数据库带来巨大压力</p>
</blockquote>
<h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><h3 id="缓存空对象"><a href="#缓存空对象" class="headerlink" title="缓存空对象"></a>缓存空对象</h3><blockquote>
<p>对查询结果为空的对象也进行缓存</p>
</blockquote>
<h4 id="代码示例"><a href="#代码示例" class="headerlink" title="代码示例"></a>代码示例</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> Forum <span class="title function_">getForumDetail</span><span class="params">(<span class="type">int</span> forumId)</span> &#123;</span><br><span class="line">    Forum forum;</span><br><span class="line">    <span class="type">String</span> <span class="variable">redisKey</span> <span class="operator">=</span> RedisKey.FORUM_DETAIL_PREFIX + forumId;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 查询缓存</span></span><br><span class="line">    <span class="type">Object</span> <span class="variable">originalForum</span> <span class="operator">=</span> redisUtil.get(redisKey);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 缓存不存在</span></span><br><span class="line">    <span class="keyword">if</span> (originalForum == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 缓存不存在，查询论坛详情</span></span><br><span class="line">        forum = lambdaQuery()</span><br><span class="line">                .select(Forum::getName, Forum::getDescription, Forum::getIcon)</span><br><span class="line">                .eq(Forum::getId, forumId)</span><br><span class="line">                .one();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 判断论坛是否存在</span></span><br><span class="line">        <span class="keyword">if</span> (forum == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 论坛不存在，缓存空字符串30秒</span></span><br><span class="line">            log.info(<span class="string">&quot;论坛不存在缓存空字符串 --- &quot;</span> + forumId);</span><br><span class="line">            redisUtil.setWithSecond(redisKey, <span class="string">&quot;&quot;</span>, <span class="number">30</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Forum</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 设置头像链接</span></span><br><span class="line">        forum.setIcon(CosUtil.getIconLink(forum.getIcon()));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 保存论坛详情到缓存</span></span><br><span class="line">        log.info(<span class="string">&quot;添加缓存 --- &quot;</span> + forum);</span><br><span class="line">        redisUtil.setWithSecond(redisKey, forum, <span class="number">1800</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> forum;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 判断是否为空缓存</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="string">&quot;&quot;</span>.equals(originalForum)) &#123;</span><br><span class="line">        log.info(<span class="string">&quot;缓存为空字符串 --- &quot;</span> + forumId);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Forum</span>();</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        log.info(<span class="string">&quot;缓存为存在对象 --- &quot;</span> + originalForum);</span><br><span class="line">        <span class="keyword">return</span> (Forum) originalForum;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="布隆过滤器"><a href="#布隆过滤器" class="headerlink" title="布隆过滤器"></a>布隆过滤器</h3><blockquote>
<p>将所有可能存在的数据哈希到一个足够大的 bitmap 中，一个一定不存在的数据会被这个 bitmap 拦截掉</p>
</blockquote>
<h1 id="缓存雪崩"><a href="#缓存雪崩" class="headerlink" title="缓存雪崩"></a>缓存雪崩</h1><blockquote>
<p>同一时间段内大量的key同时失效或者Redis服务宕机，导致大量请求到达服务器</p>
</blockquote>
<h2 id="解决方法-1"><a href="#解决方法-1" class="headerlink" title="解决方法"></a>解决方法</h2><h3 id="key-添加-ttl-随机值"><a href="#key-添加-ttl-随机值" class="headerlink" title="key 添加 ttl 随机值"></a>key 添加 ttl 随机值</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 保存论坛详情到缓存并添加随机数，防止缓存雪崩</span></span><br><span class="line">redisUtil.setWithSecond(redisKey, forum, <span class="number">1800</span> + <span class="keyword">new</span> <span class="title class_">Random</span>().nextInt(<span class="number">101</span>));</span><br></pre></td></tr></table></figure>

<h3 id="使用-Redis-集群"><a href="#使用-Redis-集群" class="headerlink" title="使用 Redis 集群"></a>使用 Redis 集群</h3><h1 id="缓存击穿"><a href="#缓存击穿" class="headerlink" title="缓存击穿"></a>缓存击穿</h1><blockquote>
<p>缓存击穿问题也叫热点key问题，就是一个高并发访问且缓存重建业务复杂的key突然失效，导致大量请求到达数据库</p>
</blockquote>
<h2 id="解决方法-2"><a href="#解决方法-2" class="headerlink" title="解决方法"></a>解决方法</h2><h3 id="互斥锁"><a href="#互斥锁" class="headerlink" title="互斥锁"></a>互斥锁</h3><blockquote>
<p>优点</p>
<ul>
<li><p>没有额外的内存消耗</p>
</li>
<li><p>保证一致性</p>
</li>
<li><p>实现简单</p>
</li>
</ul>
<p>缺点</p>
<ul>
<li><p>线程需要等待，性能受影响</p>
</li>
<li><p>可能有死锁风险</p>
</li>
</ul>
</blockquote>
<p><img src="https://gitee.com/xueweitao/images/raw/master/%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF-%E4%BA%92%E6%96%A5%E9%94%81-2023-2-814:53:58.png" alt="缓存击穿-互斥锁"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;R, ID&gt; R <span class="title function_">queryWithMutex</span><span class="params">(</span></span><br><span class="line"><span class="params">        String keyPrefix, ID id, Class&lt;R&gt; type, Function&lt;ID, R&gt; dbFallback, Long time, TimeUnit unit)</span> &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> keyPrefix + id;</span><br><span class="line">    <span class="comment">// 1.从redis查询商铺缓存</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">shopJson</span> <span class="operator">=</span> stringRedisTemplate.opsForValue().get(key);</span><br><span class="line">    <span class="comment">// 2.判断是否存在</span></span><br><span class="line">    <span class="keyword">if</span> (StrUtil.isNotBlank(shopJson)) &#123;</span><br><span class="line">        <span class="comment">// 3.存在，直接返回</span></span><br><span class="line">        <span class="keyword">return</span> JSONUtil.toBean(shopJson, type);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 判断命中的是否是空值</span></span><br><span class="line">    <span class="keyword">if</span> (shopJson != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 返回一个错误信息</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 4.实现缓存重建</span></span><br><span class="line">    <span class="comment">// 4.1.获取互斥锁</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">lockKey</span> <span class="operator">=</span> LOCK_SHOP_KEY + id;</span><br><span class="line">    <span class="type">R</span> <span class="variable">r</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isLock</span> <span class="operator">=</span> tryLock(lockKey);</span><br><span class="line">        <span class="comment">// 4.2.判断是否获取成功</span></span><br><span class="line">        <span class="keyword">if</span> (!isLock) &#123;</span><br><span class="line">            <span class="comment">// 4.3.获取锁失败，休眠并重试</span></span><br><span class="line">            Thread.sleep(<span class="number">50</span>);</span><br><span class="line">            <span class="keyword">return</span> queryWithMutex(keyPrefix, id, type, dbFallback, time, unit);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 4.4.获取锁成功，根据id查询数据库</span></span><br><span class="line">        r = dbFallback.apply(id);</span><br><span class="line">        <span class="comment">// 5.不存在，返回错误</span></span><br><span class="line">        <span class="keyword">if</span> (r == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 将空值写入redis</span></span><br><span class="line">            stringRedisTemplate.opsForValue().set(key, <span class="string">&quot;&quot;</span>, CACHE_NULL_TTL, TimeUnit.MINUTES);</span><br><span class="line">            <span class="comment">// 返回错误信息</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 6.存在，写入redis</span></span><br><span class="line">        <span class="built_in">this</span>.set(key, r, time, unit);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e);</span><br><span class="line">    &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="comment">// 7.释放锁</span></span><br><span class="line">        unlock(lockKey);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 8.返回</span></span><br><span class="line">    <span class="keyword">return</span> r;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取锁和释放锁</span></span><br><span class="line"><span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">tryLock</span><span class="params">(String key)</span> &#123;</span><br><span class="line">    <span class="type">Boolean</span> <span class="variable">flag</span> <span class="operator">=</span> stringRedisTemplate.opsForValue().setIfAbsent(key, <span class="string">&quot;1&quot;</span>, <span class="number">10</span>, TimeUnit.SECONDS);</span><br><span class="line">    <span class="keyword">return</span> BooleanUtil.isTrue(flag);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">unlock</span><span class="params">(String key)</span> &#123;</span><br><span class="line">    stringRedisTemplate.delete(key);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="逻辑过期"><a href="#逻辑过期" class="headerlink" title="逻辑过期"></a>逻辑过期</h3><blockquote>
<p>优点</p>
<ul>
<li>线程无需等待，性能较好</li>
</ul>
<p>缺点</p>
<ul>
<li><p>不保证一致性</p>
</li>
<li><p>有额外内存消耗</p>
</li>
<li><p>实现复杂</p>
</li>
</ul>
</blockquote>
<p><img src="https://gitee.com/xueweitao/images/raw/master/%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF-%E9%80%BB%E8%BE%91%E8%BF%87%E6%9C%9F-2023-2-814:56:07.png" alt="缓存击穿-逻辑过期"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;R, ID&gt; R <span class="title function_">queryWithLogicalExpire</span><span class="params">(</span></span><br><span class="line"><span class="params">        String keyPrefix, ID id, Class&lt;R&gt; type, Function&lt;ID, R&gt; dbFallback, Long time, TimeUnit unit)</span> &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> keyPrefix + id;</span><br><span class="line">    <span class="comment">// 1.从redis查询商铺缓存</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">json</span> <span class="operator">=</span> stringRedisTemplate.opsForValue().get(key);</span><br><span class="line">    <span class="comment">// 2.判断是否存在</span></span><br><span class="line">    <span class="keyword">if</span> (StrUtil.isBlank(json)) &#123;</span><br><span class="line">        <span class="comment">// 3.存在，直接返回</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 4.命中，需要先把json反序列化为对象</span></span><br><span class="line">    <span class="type">RedisData</span> <span class="variable">redisData</span> <span class="operator">=</span> JSONUtil.toBean(json, RedisData.class);</span><br><span class="line">    <span class="type">R</span> <span class="variable">r</span> <span class="operator">=</span> JSONUtil.toBean((JSONObject) redisData.getData(), type);</span><br><span class="line">    <span class="type">LocalDateTime</span> <span class="variable">expireTime</span> <span class="operator">=</span> redisData.getExpireTime();</span><br><span class="line">    <span class="comment">// 5.判断是否过期</span></span><br><span class="line">    <span class="keyword">if</span>(expireTime.isAfter(LocalDateTime.now())) &#123;</span><br><span class="line">        <span class="comment">// 5.1.未过期，直接返回店铺信息</span></span><br><span class="line">        <span class="keyword">return</span> r;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 5.2.已过期，需要缓存重建</span></span><br><span class="line">    <span class="comment">// 6.缓存重建</span></span><br><span class="line">    <span class="comment">// 6.1.获取互斥锁</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">lockKey</span> <span class="operator">=</span> LOCK_SHOP_KEY + id;</span><br><span class="line">    <span class="type">boolean</span> <span class="variable">isLock</span> <span class="operator">=</span> tryLock(lockKey);</span><br><span class="line">    <span class="comment">// 6.2.判断是否获取锁成功</span></span><br><span class="line">    <span class="keyword">if</span> (isLock)&#123;</span><br><span class="line">        <span class="comment">// 6.3.成功，开启独立线程，实现缓存重建</span></span><br><span class="line">        CACHE_REBUILD_EXECUTOR.submit(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 查询数据库</span></span><br><span class="line">                <span class="type">R</span> <span class="variable">newR</span> <span class="operator">=</span> dbFallback.apply(id);</span><br><span class="line">                <span class="comment">// 重建缓存</span></span><br><span class="line">                <span class="built_in">this</span>.setWithLogicalExpire(key, newR, time, unit);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e);</span><br><span class="line">            &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="comment">// 释放锁</span></span><br><span class="line">                unlock(lockKey);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 6.4.返回过期的商铺信息</span></span><br><span class="line">    <span class="keyword">return</span> r;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setWithLogicalExpire</span><span class="params">(String key, Object value, Long time, TimeUnit unit)</span> &#123;</span><br><span class="line">    <span class="comment">// 设置逻辑过期</span></span><br><span class="line">    <span class="type">RedisData</span> <span class="variable">redisData</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RedisData</span>();</span><br><span class="line">    redisData.setData(value);</span><br><span class="line">    redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));</span><br><span class="line">    <span class="comment">// 写入Redis</span></span><br><span class="line">    stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisData</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> LocalDateTime expireTime;</span><br><span class="line">    <span class="keyword">private</span> Object data;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
        
            <div id="toc-article">
                
  <div class="widget-wrap" id="toc-wrap">
    <h3 class="widget-title"><i class="fa fa-toc"></i> 文章目录</h3>
    <div class="widget">
      <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F"><span class="toc-text">缓存穿透</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95"><span class="toc-text">解决方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E7%A9%BA%E5%AF%B9%E8%B1%A1"><span class="toc-text">缓存空对象</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-text">代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">布隆过滤器</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9"><span class="toc-text">缓存雪崩</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95-1"><span class="toc-text">解决方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#key-%E6%B7%BB%E5%8A%A0-ttl-%E9%9A%8F%E6%9C%BA%E5%80%BC"><span class="toc-text">key 添加 ttl 随机值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-Redis-%E9%9B%86%E7%BE%A4"><span class="toc-text">使用 Redis 集群</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF"><span class="toc-text">缓存击穿</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95-2"><span class="toc-text">解决方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BA%92%E6%96%A5%E9%94%81"><span class="toc-text">互斥锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%80%BB%E8%BE%91%E8%BF%87%E6%9C%9F"><span class="toc-text">逻辑过期</span></a></li></ol></li></ol></li></ol>
    </div>
  </div>


            </div>
        
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
          


        </div>
      
      <!-- 
        
<nav id="article-nav">
  
    <a href="/wei-blog/source/SpringBoot%E6%95%B4%E5%90%88RabbitMQ/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">older</strong>
      <div class="article-nav-title">
        
          SpringBoot整合RabbitMQ
        
      </div>
    </a>
  
  
    <a href="/wei-blog/source/SpringBoot%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3%E9%99%90%E6%B5%81/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">newer</strong>
      <div class="article-nav-title">
        
          SpringBoot实现接口限流
        
      </div>
    </a>
  
</nav>

       -->
      <!-- 
        








       -->
    </footer>
  </div>
</article>
</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-classify"></i> 分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/Docker/">Docker</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/Java/">Java</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/RabbitMQ/">RabbitMQ</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/Redis/">Redis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/Spring/">Spring</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/SpringBoot/">SpringBoot</a><span class="category-list-count">13</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/SpringBoot/RabbitMQ/">RabbitMQ</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/wei-blog/categories/SpringSecurity/">SpringSecurity</a><span class="category-list-count">1</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-tag"></i> 标签</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/AOP/" rel="tag">AOP</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/JWT/" rel="tag">JWT</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/MyBatis/" rel="tag">MyBatis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/MyBatisPlus/" rel="tag">MyBatisPlus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/%E6%8B%A6%E6%88%AA%E5%99%A8/" rel="tag">拦截器</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/%E8%B7%A8%E5%9F%9F/" rel="tag">跨域</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/%E8%BF%90%E8%A1%8C%E9%94%99%E8%AF%AF/" rel="tag">运行错误</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/wei-blog/tags/%E9%80%BB%E8%BE%91/" rel="tag">逻辑</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-posts"></i> 最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/wei-blog/source/%E5%9F%BA%E4%BA%8ERedis%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/">基于Redis的分布式锁</a>
          </li>
        
          <li>
            <a href="/wei-blog/source/SpringBoot%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3%E9%99%90%E6%B5%81/">SpringBoot实现接口限流</a>
          </li>
        
          <li>
            <a href="/wei-blog/source/%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F%E3%80%81%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9%E3%80%81%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF/">(no title)</a>
          </li>
        
          <li>
            <a href="/wei-blog/source/SpringBoot%E6%95%B4%E5%90%88RabbitMQ/">SpringBoot整合RabbitMQ</a>
          </li>
        
          <li>
            <a href="/wei-blog/source/Redis%E4%B9%8BZSet/">(no title)</a>
          </li>
        
      </ul>
    </div>
  </div>


  
</aside>
        
      </div>
      <a id="totop" href="#top"></a>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      <!-- <p>
        <a href="/wei-blog/sitemap.xml">网站地图</a>
        <span> | </span><a href="/wei-blog/atom.xml">订阅本站</a>
        <span> | </span><a href="/wei-blog/about/">联系博主</a>
      </p> -->
      
      <p>
        <span>Copyright &copy; 2023 xueweitao.</span>
        <!-- <span>Theme by <a href="https://github.com/chaooo/hexo-theme-BlueLake/" target="_blank">BlueLake.</a></span>
        <span>Powered by <a href="https://hexo.io/" target="_blank">Hexo.</a></span> -->
      </p>
    </div>
  </div>
</footer>

    </div>
  </div>
  
<script src="/wei-blog/js/jquery-3.4.1.min.js"></script>


<script src="/wei-blog/js/search.json.js"></script>




<script src="/wei-blog/js/script.js"></script>








  
  



  

  

  

  

  

  

  

  
  





</body>
</html>